package edu.pw.treegrid.client.report.controller;

import java.util.Collection;
import java.util.List;

import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.form.FilterBuilder;
import com.smartgwt.client.widgets.grid.CellFormatter;
import com.smartgwt.client.widgets.grid.ListGridField;

import edu.pw.treegrid.client.format.FormatterFactory;
import edu.pw.treegrid.client.report.events.FetchReportColumnCallback;
import edu.pw.treegrid.client.report.events.FetchReportHierarchiesCallback;
import edu.pw.treegrid.client.report.events.HierachyChangeListener;
import edu.pw.treegrid.client.report.model.ReportHierarchiesDataSource;
import edu.pw.treegrid.client.report.model.ReportHierarchy;
import edu.pw.treegrid.client.report.model.ReportColumnDescriptionClient;
import edu.pw.treegrid.client.report.model.ReportDataSource;
import edu.pw.treegrid.client.report.model.ReportMetaModelDataSource;
import edu.pw.treegrid.client.report.view.HelpWindow;
import edu.pw.treegrid.client.report.view.HierarchyPanel;
import edu.pw.treegrid.client.report.view.ProgressWindow;
import edu.pw.treegrid.client.report.view.ReportPanel;
import edu.pw.treegrid.client.report.view.ReportToolbar;
import edu.pw.treegrid.client.report.view.ReportTreeGrid;
import edu.pw.treegrid.client.report.view.SettingsWindow;
import edu.pw.treegrid.shared.ReportColumnDescription;

public class ReportController {
	private ReportTreeGrid treeGrid;
	private SettingsWindow settingsWindow;
	private ReportMetaModelDataSource reportMetaModelDataSource;
	private ReportDataSource reportDataSource;
	private String reportId;
	private ReportPanel reportPanel;
	private ReportToolbar reportToolbar;
	private FilterBuilder filterBuilder;
	private HierarchyPanel hierarchyPanel;
	private boolean treeGridContructed = false;
	private List<ReportColumnDescriptionClient> columns;
	private HelpWindow helpWindow;
	private ReportHierarchiesDataSource reportHierarchiesDataSource;
	private Collection<ReportHierarchy> reportHierarchies;
	private String hierarchyId;
	private ProgressWindow progressWindow;
	
	public ReportController(String reportId, ReportPanel reportPanel) {
		init(reportId, reportPanel, null);
	}
	
	public ReportController(String reportId, ReportPanel reportPanel, String hierarchyId) {
		init(reportId, reportPanel, hierarchyId);
	}
	
	private void init(String reportId, ReportPanel reportPanel, String hierarchyId) {
		this.reportPanel = reportPanel;
		this.reportId = reportId;
		this.hierarchyId = hierarchyId;
		this.progressWindow = new ProgressWindow();
		this.progressWindow.start();
		this.reportMetaModelDataSource = new ReportMetaModelDataSource(this.reportId);
		this.reportDataSource = new ReportDataSource(this.reportId);
		this.reportToolbar = new ReportToolbar(this, this.reportId);
		this.reportPanel.addMember(this.reportToolbar);
		
		this.reportMetaModelDataSource.fetchReportColumns(new FetchReportColumnCallback() {
			public void reportColumns(List<ReportColumnDescriptionClient> columns) {
				ReportController.this.progressWindow.updateStatus("Odebrano kolumny raportu", 30);
				ReportController.this.columns = columns;
				initReportHierarchyDataSource();
			}
		});
	}
	
    protected void initReportHierarchyDataSource() {                
        this.reportHierarchiesDataSource = new ReportHierarchiesDataSource(reportId, columns);
        this.reportHierarchiesDataSource.fetchReportHierarchies(new FetchReportHierarchiesCallback() {
            @Override
            public void reportHierarchies(Collection<ReportHierarchy> values) {
            	ReportController.this.progressWindow.updateStatus("Odebrano hierarchie raportu", 60);
                ReportController.this.reportHierarchies = values;
                initDataSource(columns);
                initWindow(ReportController.this.columns);
                ReportController.this.progressWindow.updateStatus("Inicjalizacja hierarchii", 90);
                ReportHierarchy rh = null;
                if(ReportController.this.hierarchyId != null) {
                	for(ReportHierarchy h : values) {
                		if(ReportController.this.hierarchyId.equals(h.getName())) {
                			rh = h;
                		}
                	}
                }
                ReportController.this.progressWindow.finish();
                if(rh != null) {
                	ReportController.this.hierarchyPanel.setReportHierarchy(rh);
                	onSettingsOK();
                }
                else {
                	onShowSettings();
                }                
            }
        });
    }
	
	public void onPrintPreview() {
		Canvas.showPrintPreview(treeGrid);
	}

	public void onShowSettings() {
		settingsWindow.show();
	}

	public void onSettingsOK() {
		if(!this.hierarchyPanel.isValidHierarchy()) {
			SC.say("Należy wybrać co najmniej jedną kolumnę!");
			return;
		}
		settingsWindow.okButton.setDisabled(false);
		settingsWindow.cancelButton.setDisabled(false);
		if(!treeGridContructed) {
			constructTreeGrid();
			initFormatters(this.columns);
			treeGridContructed = true;
		}
    	reportDataSource.setHierarchy(hierarchyPanel.getHierarchy().duplicate());
    	treeGrid.fetchData(filterBuilder.getCriteria());
    	settingsWindow.hide();
	}

	private void initDataSource(
			List<ReportColumnDescriptionClient> columns) {
		ReportController.this.progressWindow.updateStatus("Inicjalizacja źródła danych", 70);
		this.reportDataSource.setColumns(columns);
		this.filterBuilder = new FilterBuilder();
		this.filterBuilder.setDataSource(reportDataSource);
	}
	
	private void initWindow(List<ReportColumnDescriptionClient> columns) {
		ReportController.this.progressWindow.updateStatus("Inicjalizacja widoku", 75);
		this.hierarchyPanel = new HierarchyPanel(columns, this, this.reportHierarchies);
		this.settingsWindow = new SettingsWindow(this, this.hierarchyPanel, this.filterBuilder);
	}
	
	private void constructTreeGrid() {	
		treeGrid = new ReportTreeGrid(reportDataSource);
		
		reportDataSource.addHierarchyChangeListener(new HierachyChangeListener() {
			public void onHierarchyChanged(Collection<ReportColumnDescriptionClient> columns) {
				for(ReportColumnDescriptionClient c : columns) {
					if(c.getCategory().isVisibleAsReportColumn()) {
						treeGrid.showField(c.getName());
					}
					else {
						treeGrid.hideField(c.getName());
					}
				}
			}
		});
/*		
		String msg = "";
		for(ReportColumnDescriptionClient rc : this.columns) {
			for(ListGridField field : treeGrid.getFields()) {
				if(field.getValueField().equals(rc.getName())) {
					msg += "EQUALS <br/>\n";
					if(rc.getWidth() != null && rc.getWidth().length() > 0) {
						field.setWidth(rc.getWidth());
					}
				}
				msg += field.getDisplayField() + " " + field.getValueField() + " " + rc.getName() + " width: " + rc.getWidth() + "<br/>\n";
			}
		}
		SC.say(msg);
*/
		
		this.reportPanel.addMember(treeGrid);
        this.reportPanel.markForRedraw();
	}
	
	private void initFormatters(List<ReportColumnDescriptionClient> columns) {
		for(ReportColumnDescriptionClient rcd: columns) {
			if(rcd.getFormat() != null && rcd.getFormat().length() > 0) {
				ListGridField field = this.treeGrid.getField(rcd.getName());				
				CellFormatter cf = FormatterFactory.newFormatter(rcd.getType(), rcd.getFormat());
				field.setCellFormatter(cf);
			}
		}
		//this.treeGrid.getField(ReportColumnDescription.NAME_COLUMN).setFrozen(true);
	}

	public void onSettingsCancel() {
		if(treeGridContructed) {
			settingsWindow.hide();
		}
		else {
			SC.say("Musisz podać hierarchie!");
		}
	}

	public void onHierarchyChanged() {
		if(hierarchyPanel.isValidHierarchy()) {
			settingsWindow.okButton.setDisabled(false);
			settingsWindow.cancelButton.setDisabled(false);
		}
		else {
			settingsWindow.okButton.setDisabled(true);
			settingsWindow.cancelButton.setDisabled(true);
		}
	}

	public void onHelp() {
		if(helpWindow == null) {
			helpWindow = new HelpWindow(columns);
		}
		
		helpWindow.show();
	}
	
    public void onReportHierarchyChanged(ReportHierarchy h) {
        this.hierarchyPanel.setReportHierarchy(h);
        this.onHierarchyChanged();
    }
}
